package com.atguigu.bookcity.config;

import com.atguigu.bookcity.filter.CustomAuthenFilter;
import com.atguigu.bookcity.realm.CustomHashedCredentialsMatcher;
import com.atguigu.bookcity.realm.CustomSessionManager;
import com.atguigu.bookcity.realm.UserRealm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {


    //创建shiroFilter
    @Bean(name = "shiroFilterFactoryBean")
    public ShiroFilterFactoryBean
    getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager
    ) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
        //配置自定义过滤器
        Map<String, Filter> filters = shiroFilterFactoryBean.getFilters();
        filters.put("authc", new CustomAuthenFilter());
        // 限制同一帐号同时在线的个数 fixme 未生效
        //filters.put("kickout",kickOutSessionControlFilter);
        shiroFilterFactoryBean.setFilters(filters);

        //配置系统受限资源
        //配置系统公共资源
        HashMap<String, String> map = new HashMap<>();
        map.put("/bookcity/order/getRank", "anon");//anon 设置为公共资源  放行资源放在下面
        map.put("/bookcity/order/**", "authc");
        //map.put("/bookcity/purchase/**", "authc");//购书申请接口，测试环境先注释
        map.put("/bookcity/user/modifyPassword", "authc");
        map.put("/bookcity/user/getUserInfo", "authc");
        map.put("/bookcity/shopping-cart/**", "authc");
        map.put("/**", "anon");
        //默认认证界面
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean;
    }

    //创建安全管理器
    @Bean
    public DefaultWebSecurityManager
    getDefaultWebSecurityManager(UserRealm realm,
                                 CustomSessionManager sessionManager,
                                 RedisCacheManager cacheManager) {
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        //自定义sessionManager
        defaultWebSecurityManager.setRealm(realm);
        defaultWebSecurityManager.setSessionManager(sessionManager);
        // 自定义缓存实现 使用redis
        defaultWebSecurityManager.setCacheManager(cacheManager);
        return defaultWebSecurityManager;
    }

    @Bean
    public UserRealm getRealm(RedisCacheManager cacheManager,
                              //自定义hashed凭证匹配器
                              CustomHashedCredentialsMatcher credentialsMatcher) {
        UserRealm userRealm = new UserRealm();
        //设置hashed凭证匹配器
        //HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        //设置md5加密
        credentialsMatcher.setHashAlgorithmName("md5");
        //设置散列次数
        credentialsMatcher.setHashIterations(1024);
        userRealm.setCredentialsMatcher(credentialsMatcher);

        //开启缓存管理器
        userRealm.setCachingEnabled(true);
        userRealm.setAuthenticationCachingEnabled(true);
        userRealm.setAuthorizationCachingEnabled(true);
        userRealm.setCacheManager(cacheManager);
        return userRealm;
    }

    //自定义sessionManager
    @Bean
    public CustomSessionManager sessionManager() {
        CustomSessionManager customSessionManager = new CustomSessionManager();
        customSessionManager.setSessionDAO(redisSessionDAO());
        return customSessionManager;
    }


    @Bean
    public RedisCacheManager cacheManager() {
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());
        return redisCacheManager;
    }


    @Bean
    public RedisSessionDAO redisSessionDAO() {
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());
        return redisSessionDAO;
    }

    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.port}")
    private String port;
    @Value("${spring.redis.password}")
    private String password;
    @Value("${spring.redis.database}")
    private Integer database;


    public RedisManager redisManager() {
        RedisManager redisManager = new RedisManager();
        redisManager.setHost(host + ":" + port);
        redisManager.setPassword(password);
        redisManager.setDatabase(database);
        return redisManager;
    }


}
